home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / DeveloperLabs / Lab3 / Solution / Controller.m < prev    next >
Text File  |  1995-06-12  |  6KB  |  220 lines

  1. /*  Controller.m --- Main controller object for the TextLab program.
  2. **  Authors: Bruce Blumberg and Ali Ozer, NeXT Developer Support Group
  3. */
  4.  
  5. // Controller object is the central object in TextLab.  It manages the
  6. // windows, open/save panels, and menu commands. 
  7.  
  8. #import "Controller.h"
  9. #import "TextView.h"
  10. #import <appkit/Application.h>
  11. #import <objc/typedstream.h>
  12. #import <appkit/FontManager.h>
  13.  
  14. // Extension for TextLab archive files and length of the extension
  15.  
  16. #define EXTENSION    ".tl"
  17. #define EXTENSIONLEN 3
  18.  
  19. @implementation Controller
  20.  
  21. // We subclass the Controller "new" so that we can set the application's
  22. // delegate to point to the Controller object. This way open file
  23. // requests from the Workspace get routed to the Controller's 
  24. // appOpenFile:type: and appAcceptsAnotherFile methods.
  25.  
  26. + new
  27. {
  28.   self = [super new];
  29.   [NXApp setDelegate:self];
  30.   
  31.   // create instances of support objects
  32.   openReq = [OpenPanel new];
  33.   saveReq = [SavePanel new];
  34.   fontReq = [FontManager new]; 
  35.   
  36.   return self;
  37. }
  38.  
  39. - showError: (char *)errorMessage
  40. {
  41.   NXRunAlertPanel (NULL,errorMessage,"OK",NULL,NULL);
  42. }
  43.  
  44. // newTextView: is invoked in response to a new empty window request. It
  45. // creates a new window containing a TextView. Note that we want new windows 
  46. // to be offset from each other by some amount; hence the use of wRect.
  47.  
  48. #define ORIGX 100.0
  49. #define ORIGY 100.0
  50. static NXRect wRect = {{ORIGX, ORIGY},{500.0,400.0}};
  51.  
  52. - newTextView:sender
  53. {   
  54.     id newTextView;
  55.     NXOffsetRect(&wRect, 20.0, -20.0);
  56.     if (wRect.origin.y < 0) {wRect.origin.y = ORIGY; wRect.origin.x = ORIGX;}
  57.     newTextView = [TextView newFrame:&wRect];
  58.     [[newTextView window] setDelegate:self];     
  59.     return self;
  60. }
  61.  
  62. // appAcceptsAnotherFile is an application delegate method which 
  63. // returns whether it is OK for the application to try to open more files
  64. // with the appOpenFile:type: method. TextLab can indeed open multiple
  65. // windows, so we return YES.
  66.  
  67. -(BOOL) appAcceptsAnotherFile:sender
  68. {
  69.   return (YES);
  70. }
  71.  
  72.  
  73. // appOpenFile:type: is called to open the specified file. It is normally
  74. // called by the Application object in response to open requests from the
  75. // Workspace. Here we also route the open requests from the OpenPanel
  76. // to this method (see openRequest:).
  77.  
  78. -(int) appOpenFile:(char *)fileName type:(char *)fileType
  79. {
  80.    return [self openFile:fileName];  
  81. }
  82.  
  83. // openRequest: opens a new file. It puts up a open panel, and, if the user
  84. // doesn't cancel, it reads the specified archive file. If the selected file
  85. // is not a proper archive file, then openRequest: will complain.
  86.  
  87. - openRequest:sender
  88. {
  89.     const char *fileName;
  90.     const char *const types[2] = {"tl",NULL};
  91.     int ok;
  92.  
  93.     if ([openReq runModalForTypes:types] && (fileName =[openReq filename])) {
  94.     [self openFile:fileName];
  95.     }
  96.     else
  97.     [self showError:"No file chosen or could not open file"];
  98.     return self;
  99. }
  100.  
  101. -(int) openFile:(const char *)fileName
  102. {
  103.    id win;
  104.    NXTypedStream *typedStream;
  105.    
  106.     if(!(typedStream = NXOpenTypedStreamForFile(fileName,NX_READONLY))){
  107.     [self showError:"error on opening file"];
  108.     return NO;
  109.     }
  110.     else {
  111.     win = NXReadObject(typedStream);
  112.     NXCloseTypedStream(typedStream);
  113.     [win setTitle:fileName];
  114.          [[win display] makeKeyAndOrderFront:self];
  115.     return YES;
  116.     } 
  117. }
  118.  
  119.  
  120. // saveRequest: saves the current window under its default name (found in
  121. // the title bar). Note that if the title bar is empty or the default title
  122. // is "Untitled" then saveRequest: will put up a save panel, giving the user
  123. // a chance to specify a real title.
  124.  
  125. - saveRequest:sender
  126. {
  127.     const char *fileName;
  128.     const char *const types[2] = {"tl",NULL};
  129.     
  130.     id curWin = [NXApp mainWindow];
  131.     [saveReq setRequiredFileType:types[0]];
  132.     
  133.     if (curWin == nil) 
  134.     [self showError:"No active window to save."];
  135.     else {
  136.     // Check to see if the current window is titled and the title is not
  137.     // "Untitled". If so, save the file, else put up a save panel...
  138.     fileName = [curWin title];
  139.     if (strcmp (fileName, "Untitled"))
  140.         [self saveWindow:curWin inPath:fileName];
  141.     else [self saveInRequest:sender];
  142.     }
  143.     return self;
  144. }
  145.  
  146. // saveInRequest: gives the user a chance to save the current window
  147. // under a new name. 
  148.  
  149. - saveInRequest:sender
  150. {
  151.     const char *fileName;
  152.     const char *const types[2] = {"tl",NULL};
  153.     
  154.     id curWin = [NXApp mainWindow];
  155.     [saveReq setRequiredFileType:types[0]];
  156.  
  157.     if (curWin == nil) 
  158.     [self showError:"No active window to save."];
  159.     else {
  160.     // Get a file name from the user; use title of the window as default.
  161.     if (([saveReq runModalForDirectory:"." file:[curWin title]]) &&
  162.           (fileName = [saveReq filename])) 
  163.         [self saveWindow:curWin inPath:fileName];
  164.     }
  165.     return self;
  166. }
  167.  
  168.  
  169. // saveWindow writes a window out the archive file whose name is specified
  170. // by the second argument. The title of the current window is also set 
  171. // accordingly. 
  172.  
  173. - saveWindow:(id)win inPath:(const char *)name
  174. {    
  175.     NXTypedStream *typedStream;
  176.     
  177.     [win setTitle:name];
  178.     typedStream = NXOpenTypedStreamForFile(name,NX_WRITEONLY);
  179.     NXWriteRootObject(typedStream,win);
  180.     NXCloseTypedStream(typedStream);
  181.     return self;
  182. }
  183.  
  184. // Printing is rather simple; just send printPSCode: to the text view
  185. // you wish to print. The print panel will automatically pop up and unless
  186. // the user cancels the printout the text view will be printed.
  187.  
  188. - printRequest:sender
  189. {
  190.     id curText = [[[NXApp mainWindow] contentView] docView];
  191.  
  192.     if (curText == nil) [self showError:"No active window to print."];
  193.     else {
  194.     [[[NXApp printInfo] setHorizCentered:NO] setVertCentered:NO];
  195.         [curText printPSCode:self];
  196.     }
  197.     return self;
  198. }
  199.  
  200. // closeRequest closes the current window by simulating a click on the
  201. // closebutton. A check should probably be added to give the user the 
  202. // option of saving the window before closing
  203.  
  204. - closeRequest:sender
  205. {
  206.    [[NXApp mainWindow] performClose:sender];
  207.    return self;
  208. }
  209.  
  210. // This method will get called before a window is closed and
  211. // will give the user an opportunity to save their file. It then returns
  212. // self indicating that the window may be closed.
  213.  
  214. - windowWillClose:(id)whichWin
  215. {
  216.     return self;
  217. }
  218.     
  219. @end
  220.